package com.hejing.bpeldesign.bpel;


import com.hejing.bpeldesign.model.BpelEdge;
import com.hejing.bpeldesign.model.BpelNode;

import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;
import java.awt.geom.AffineTransform;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

public class BpelDiagramPanel extends JPanel {
    private final List<BpelNode> nodes;
    private final List<BpelEdge> edges;
    private final Map<String, Image> iconMap = new HashMap<>();

    private static final java.util.Set<String> imageOnlyTypes = Set.of(
            "while", "whilestart", "whileend",
            "switch", "switchstart", "switchend",
            "case", "otherwise", "throw", "expression"
    );

    private double scale = 1.0;

    public BpelDiagramPanel(List<BpelNode> nodes, List<BpelEdge> edges) {
        this.nodes = nodes;
        this.edges = edges;
        setBackground(UIManager.getColor("EditorPane.background"));
        setOpaque(true);
        this.loadIcons();
        this.setBorder(BorderFactory.createEmptyBorder(50, 50, 50, 50)); // 上左右右都 padding
        addMouseWheelListener(new MouseWheelListener() {
            @Override
            public void mouseWheelMoved(MouseWheelEvent e) {
                if (e.isControlDown()) {
                    if (e.getWheelRotation() < 0) {
                        scale *= 1.1;
                    } else {
                        scale /= 1.1;
                    }
                    scale = Math.max(0.1, Math.min(scale, 5.0)); // 限制缩放范围
                    revalidate();
                    repaint();
                } else {
                    // 鼠标滚轮上下滚动
                    Container parent = getParent();
                    if (parent instanceof JViewport) {
                        JViewport viewport = (JViewport) parent;
                        Point p = viewport.getViewPosition();
                        p.translate(0, e.getUnitsToScroll() * 15); // 每个滚动单位5px
                        p.y = Math.max(0, Math.min(p.y, getHeight() - viewport.getHeight()));
                        viewport.setViewPosition(p);
                    }
                }
            }
        });
    }

    @Override
//    public Dimension getPreferredSize() {
//        int maxX = 0, maxY = 0;
//        for (BpelNode node : nodes) {
//            maxX = Math.max(maxX, node.x + node.width);
//            maxY = Math.max(maxY, node.y + node.height);
//        }
//        return new Dimension((int) (maxX * scale) + 200, (int) (maxY * scale) + 200);
//    }
    public Dimension getPreferredSize() {
        int maxX = 0, maxY = 0;
        int minX = Integer.MAX_VALUE, minY = Integer.MAX_VALUE;
        for (BpelNode node : nodes) {
            maxX = Math.max(maxX, node.x + node.width);
            maxY = Math.max(maxY, node.y + node.height);
            minX = Math.min(minX, node.x);
            minY = Math.min(minY, node.y);
        }

        int padding = 50;
        int width = (int) ((maxX - minX) * scale) + padding * 2;
        int height = (int) ((maxY - minY) * scale) + padding * 2;
        return new Dimension(width, height);
    }


    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        Graphics2D g2d = (Graphics2D) g;
        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        // 平移加缩放：先平移再缩放
        int padding = 50;
        AffineTransform transform = g2d.getTransform();
        transform.translate(padding, padding);
        transform.scale(scale, scale);
        g2d.setTransform(transform);

        // Draw nodes
        for (BpelNode node : nodes) {
            Image icon = iconMap.get(node.type.toLowerCase());

            if (icon != null) {

                int iconW = icon.getWidth(this);
                int iconH = icon.getHeight(this);

                int iconX = node.x + (node.width - iconW) / 2;  // 左右居中
                int iconY = node.y;                             // 上贴边

                // ✅ 绘制图标
                g2d.drawImage(icon, iconX, iconY, this);

                if (!imageOnlyTypes.contains(node.type)) {
                    // ✅ 显示文字在图标下方区域（节点下半部分）
                    FontMetrics fm = g2d.getFontMetrics();
                    int textWidth = fm.stringWidth(node.name);
                    int textX = node.x + (node.width - textWidth) / 2;
                    int textY = node.y + node.height - 5; // 调整一点下边缘位置
                    g2d.setColor(Color.BLACK);
                    g2d.drawString(node.name, textX, textY);
                }


//                if (imageOnlyTypes.contains(node.type)) {
//                    // ✅ 整个节点都显示图片，不显示文字
//                    g2d.drawImage(icon, node.x, node.y, node.width, node.height, this);
//                } else {
//                    // ✅ 正常节点，上半图，下半字
//                    g2d.drawImage(icon, node.x, node.y, node.width, node.height / 2, this);
//
//                    FontMetrics fm = g2d.getFontMetrics();
//                    int textWidth = fm.stringWidth(node.name);
//                    int textHeight = fm.getAscent();
//                    int textX = node.x + (node.width - textWidth) / 2;
//                    int textY = node.y + (node.height * 3 / 4) + (textHeight / 2);
//                    g2d.setColor(Color.BLACK);
//                    g2d.drawString(node.name, textX, textY);
//                }
            } else {
                // 没图的默认白框+文字
                g2d.setColor(Color.WHITE);
                g2d.fillRect(node.x, node.y, node.width, node.height);
                g2d.setColor(Color.BLACK);
                g2d.drawRect(node.x, node.y, node.width, node.height);

                FontMetrics fm = g2d.getFontMetrics();
                int textWidth = fm.stringWidth(node.name);
                int textHeight = fm.getAscent();
                int textX = node.x + (node.width - textWidth) / 2;
                int textY = node.y + (node.height + textHeight) / 2 - 3;
                g2d.drawString(node.name, textX, textY);
            }

        }

        // Draw edges
        for (BpelEdge edge : edges) {
            Point p1 = getAnchorPoint(edge.sourceNode, edge.terminal.charAt(0));
            Point p2 = getAnchorPoint(edge.targetNode, edge.terminal.charAt(2));
            drawArrowLine(g2d, p1.x, p1.y, p2.x, p2.y);
        }
    }

    private Point getAnchorPoint(BpelNode node, char anchor) {
        int x = node.x;
        int y = node.y;
        int w = node.width;
        int h = node.height;

        switch (anchor) {
            case '1': return new Point(x + w / 2, y);               // Top center
            case '2': return new Point(x, y + h / 2);               // Left center
            case '5': return new Point(x + w / 2, y + h);           // Bottom center
            case '8': return new Point(x + w, y + h / 2);           // Right center
            case 'A': return new Point(x + w / 2, y);               // Top center (target)
            case 'B': return new Point(x, y + h / 2);               // Left center (target)
            case 'E': return new Point(x + w / 2, y + h);           // Bottom center (target)
            case 'D': return new Point(x + w, y + h / 2);           // Right center (target)
            default:  return new Point(x + w / 2, y + h / 2);       // Fallback center
        }
    }

    private void drawArrowLine(Graphics2D g, int x1, int y1, int x2, int y2) {
        g.setColor(new Color(60, 90, 150)); // ✅ 柔和蓝色
        g.setStroke(new BasicStroke(1.5f));
        g.drawLine(x1, y1, x2, y2);

        double angle = Math.atan2(y2 - y1, x2 - x1);
        int arrowLength = 10;
        int arrowWidth = 6;

        int xArrow1 = x2 - (int)(arrowLength * Math.cos(angle - Math.PI / 6));
        int yArrow1 = y2 - (int)(arrowLength * Math.sin(angle - Math.PI / 6));
        int xArrow2 = x2 - (int)(arrowLength * Math.cos(angle + Math.PI / 6));
        int yArrow2 = y2 - (int)(arrowLength * Math.sin(angle + Math.PI / 6));

        Polygon arrowHead = new Polygon();
        arrowHead.addPoint(x2, y2);
        arrowHead.addPoint(xArrow1, yArrow1);
        arrowHead.addPoint(xArrow2, yArrow2);

        g.fillPolygon(arrowHead); // ✅ 填充箭头
    }

    private static final Map<String, String> typeToIcon = Map.ofEntries(
            Map.entry("assign", "assign"),
            Map.entry("case", "case"),
            Map.entry("empty", "empty"),
            Map.entry("expression", "expression"),
            Map.entry("ext-flow", "ext-flow"),
            Map.entry("ext-alarm", "ext-alarm"),
            Map.entry("ext-onmessage", "ext-onmessage"),
            Map.entry("ext-pick", "ext-pick"),
            Map.entry("ext-sequence", "ext-sequence"),
            Map.entry("switch", "ext-switch"),
            Map.entry("while", "ext-while"),
            Map.entry("flow-end", "flow-end"),
            Map.entry("flow-start", "flow-start"),
            Map.entry("invoke", "invoke-bean"),
            Map.entry("invokewf", "invoke-wf"),
            Map.entry("objectcompose", "object_compose"),
            Map.entry("otherwise", "otherwise"),
            Map.entry("pick-end", "pick-end"),
            Map.entry("pick-start", "pick-start"),
            Map.entry("receive", "receive"),
            Map.entry("reply", "reply"),
            Map.entry("switchend", "switch-end"),
            Map.entry("switchstart", "switch-start"),
            Map.entry("terminate", "terminate"),
            Map.entry("terminateall", "terminate_all"),
            Map.entry("throw", "throw"),
            Map.entry("wait", "wait"),
            Map.entry("whileend", "while-end"),
            Map.entry("whilestart", "while-start"),
            Map.entry("xmlcompose", "xmlc"),
            Map.entry("xmlparse", "xmlp")
    );
    private  void loadIcons() {


        for (String type : typeToIcon.keySet()) {
            String imageName = typeToIcon.get(type);
//            ImageIcon icon = new ImageIcon(getClass().getClassLoader().getResource("icons/enactity/" + imageName + ".png"));
//            iconMap.put(type.toLowerCase(), icon.getImage());


            String path = "icons/enactivity/" + imageName + ".png";
            java.net.URL resource = getClass().getClassLoader().getResource(path);

            if (resource != null) {
                ImageIcon icon = new ImageIcon(resource);
                iconMap.put(type, icon.getImage());
            } else {
                System.err.println("Warning: Icon not found for type: " + type + " at path: " + path);
            }
        }
    }

}
